package WIAB::Controller::Edit;
use strict;
use warnings;
use base 'Catalyst::Controller';
use Path::Class;
use File::Slurp;
use File::Basename;
use File::Path;

=head1 NAME

WIAB::Controller::Edit - Catalyst Controller

=head1 SYNOPSIS

See L<WIAB>

=head1 DESCRIPTION

Catalyst Controller.

=head1 METHODS


=head2 auto

Makes sure user is logged in.

=cut

sub auto : Private {
    my ($self, $c ) = @_;
    unless ($c->user) {
        $c->res->body('Permission Denied');
        $c->res->redirect($c->uri_for('/user/login'));
        return;
    }
}


=head2 content

Gets information about the page to be edited and sends it off to the
template for editing.

=cut

sub content : Local {
    my ($self, $c) = @_;
    my $path = $c->req->args;
    my $base_dir = Path::Class::Dir->new($c->config->{content});
    map { $_ = _remove_special_chars($_)} @$path;
    my $content_dir = join '/', @$path;
    my $file = $base_dir->subdir("$content_dir")->file('index.pod');
    $c->stash->{show_title} = 1 if $path; # edit page title too if not
                                          # at content root

    my $template;
    if (@{$c->req->args}) {
        # skip this for home page which has $site_title
        $c->stash->{page_title} = _add_spaces($c->req->args->[-1]);
    }
        eval {
            $c->stash->{Content} = File::Slurp::read_file("$file");
        };
    my $dest = [];
        if ($@) {
        $c->stash->{Error} = "There was a problem processing the page.  Either try something different, or contact the site admin " . $c->config->{admin_email}  . " with a note of the time that the request was made";
        $c->log->debug("The user " . $c->user . " tried to edit a page at /content/" . join '/', @$path . "resulting in this error: $@");
        $template = 'error.tt';
    }
    $c->stash->{form_dest} = '/edit/write_content'. '/' . join '/', @$path;
    $template = 'edit.tt' unless $template;
    $c->stash->{template} = $template;
}

=head2 write_content

Called from the form generated by L<#content>.  Works out what to
write and sends it off to L<WIAB::Model::Edit> to be written.

=cut
    
sub write_content : Local {
    my ($self, $c) = @_;
    my $path = $c->req->args;
    my ( $dest, $log);
    my $orig_title = $c->req->param('orig_title');
    my $title = $c->req->param('page_title');

    if ( $orig_title ne $title) {
        # we're going to move the page
        ( $dest, $c->stash->{Error}, $log ) =
            $c->model('Edit')->
                move_and_write_content
                    ($c->req->param('page_content'), $title, $path);
        if (! $dest) {
            $c->stash->{template} = 'error.tt'
                }
        elsif ($log) {
            $c->log->debug($c->user . " caused the following error: $log");
            $c->stash->{template} = 'error.tt'
        }
        else {
            unshift @$dest, 'content';
            $c->res->redirect($c->uri_for('/' . join '/', @$dest));
            $c->detach();
        }
    }

    else {
        # we're on an edit.
        ( $dest, $c->stash->{Error}, $log ) =
            $c->model('Edit')->
                write_content($c->req->param('page_content'), $title, $path);

        if ($log) {
            $c->log->debug($c->user . "caused the following error: $log");
            $c->stash->{template} = 'error.tt'
        }
        else {
            # quick fix for crappy code - there might be a logic error
            # with setting $dest somewhere.  It should always be an
            # array ref, but I didn't know when I first wrote this.
            $DB::single=1;
            ref($dest) eq 'ARRAY'?
                $c->res->redirect($c->uri_for(join '/', @$dest)):
                    $c->res->redirect($c->uri_for('/'. $dest));
            $c->detach();
        }
    }
}

=head2 newpage

provides an edit page to create at or beneath the level of the
referring page.  Referring page is derived from the path parts after
/edit/newpage

=cut

sub newpage : Local{
    my ($self, $c) = @_;
    shift (@{$c->req->args}) if $c->req->args->[0] eq 'content';
    my $path = join '/', @{$c->req->args};
    my $base_dir = Path::Class::Dir->new($c->config->{content});
    my $sub_dir = $base_dir->subdir($path);
    my $template;
    if (!-e $sub_dir) {
        $c->stash->{Error} = "Parent path $path does not exist.  Please try again.  If the problemn persists contact the site administrator: " . $c->config->{admin_email};
        $c->log->debug($c->user . " tried to add a page beneath the non-esistent subdir $sub_dir");
        $template = 'error.tt';
    }
    else {
        $template = 'edit.tt';
        $c->stash->{show_title} = 1;
        $c->stash->{form_dest} = '/edit/write_newpage';
        $c->stash->{form_dest} = $c->stash->{form_dest}. '/'. $path;
    }
    $c->stash->{template} = $template;
}

=head2 write_newpage

Writes the newpage to disk after from the data privided by L<#newpage>

=head2

=cut

sub write_newpage : Local {
    my ($self, $c) = @_;
    $DB::single=1;
    my $path = $c->req->args;
    # content and location logic
    my $content = $c->req->param('page_content');
    my $title = _remove_special_chars($c->req->param('page_title'));
    if ( @$path ) {
        shift @$path  unless $c->req->param('write_to_subdir') == 1;
    }

    # set up for write

    my $dest;
    ($dest, $c->stash->{Error}) =
        $c->model('Edit')->addpage($title, $content, $path);
    
    if ($c->stash->{Error}) {
        $c->detach($dest);
        $c->stash->{template} = 'error.tt';
        $c->detach($dest);
        return;
    }
    else {
        $c->res->redirect($c->uri_for($dest));
        $c->detach();
    }

}

=head2 delete

Checks that it it legal, then deletes legal-to-delete (i.e. leaf
pages).  TODO - should really have a confirm dialog here, javascript
alert?

=cut

sub delete : Path {
    my ($self, $c) = @_;
    my $path = $c->req->args;
    shift @$path;
    my $action = shift @$path;
    if ($action eq 'content') {
        $c->detach('del_content', [$path]);
        return;
    }
    else {
        $c->stash->{Error} = "invalid action";
        $c->log->debug('invalid action requested: ' . $c->req->path);
    }
    $c->stash->{template} = 'error.tt';
}

=head2 del_content

=== REFACTOR ALERT ===
Worker sub for L<#delete>.  Actually does the deleting (should
be part of WIAB::Model::Edit instead.

=cut

sub del_content : Private {
    my ($self, $c, $path ) = @_;
    if (! @$path) {
        $c->stash->{Error} =
            "Invalid action - Unable to delete home page - edit instead.";
        $c->stash->{template} = 'error.tt';
    }
    else {
        my $dir = Path::Class::Dir->new($c->config->{content})
            ->subdir(join '/', @$path);
        if ( $c->model('Edit')->are_children($dir) ) {
            $c->stash->{Error} = "This page, " . join '/', @$path . " has subpages please go back and delete and/or move the subpages first";
            $c->stash->{template} = 'error.tt';
        }
        else {
            # TODO:  fix for VC/svn model
            eval {
                rmtree("$dir");
            };
            if ($@) {
                $c->log->debug("error encountered deleting page $@");
                $c->stash->{Error} = "There was a problem deleting the page please contact the site administrator " . $c->config->{admin_email} . " if the problem persists";
                $c->stash->{template} = 'error.tt';
            }
            else {
                $c->flash->{Notice} = "Page " . join ('/', @$path) . "deleted.  If this was a mistake, use the back button on your browser to go and retrieve the text now.";
                pop @$path;
                $c->res->redirect($c->uri_for('/content/'. join '/', @$path));
                return;
            }
        }
    }
}

=head2 _remove_special_chars

Takes a string, and returns the string with _ instead of spaces.  For
getting rid of %20 in links.  This should be factored out into a
utility package.

=cut
sub _remove_special_chars {
    my $dirname = shift;
    $dirname =~ s/\s+/_/g;
    return $dirname;
}

=head2 _add_spaces

Takes a string, and returns the string with spaces instead of
underscores.  For avoiding _ in link text.  This should be factored
out into a utility package as this code is duplicated elsewhere.

=cut


sub _add_spaces {
    my $txt = shift;
    $txt =~ s/_+/ /g;
    return $txt;
}

=head1 AUTHOR

Kieren Diment

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;
